﻿using System;
using System.Collections.Generic;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.GamePlay;
using LFloatMath.Collision2D;
using LFloatMath.Math;

namespace IQIGame.Onigao.Logic
{
    public class TargetSelect : ITargetSelect, IReusableClass
    {
        public uint MaxStore => 5;

        public virtual void OnReset()
        {
            this.targets.Clear();
        }

        public long guid;
        
        public bool inputSelect { get; set; }
        public virtual bool selectByUnit { get; }

        public virtual ETargetSelectType selectType { get; }
        /// <summary>
        /// 目标阵营类型
        /// </summary>
        public ETargetRelation targetRelation { get; set; } = ETargetRelation.Enemy;
        
        public Unit self { get; set; }

        public List<Unit> targets = new List<Unit>(5);
        public Dictionary<Unit, int> targetsScreen = new Dictionary<Unit, int>();
        
        private Action<List<CollisionComponent>, List<Unit>> mOnHit;
        private Predicate<CollisionComponent> mCondition;

        // 目标选择可选目标的最大范围
        public LFloat targetDisRange = -LFloat.one;
        
        public void Initialize(Unit unit, TargetSelectConfig rConfig)
        {
            this.guid = rConfig.guid;
            this.self = unit;
            this.mOnHit = this.OnHit;
            this.mCondition = this.TargetCondition;
            this.targetRelation = (ETargetRelation)rConfig.targetRelation;
            this.inputSelect = rConfig.forceInput;
            this.OnInitialize(rConfig);
        }
        
        public void Initialize(Unit unit, List<int> rTabConfig)
        {
            this.guid = 0;
            this.self = unit;
            this.inputSelect = false;
            this.mOnHit = this.OnHit;
            this.mCondition = this.TargetCondition;
            if (rTabConfig != null && rTabConfig.Count > 0)
            {
                this.targetRelation = (ETargetRelation)rTabConfig[0];
            }
            this.OnInitialize(rTabConfig);
        }

        private bool TargetCondition(CollisionComponent rTarget)
        {
            var rUnit = rTarget.unit;
            if (rUnit == null || 
                rUnit.IsDead(true) || 
                rUnit.IsTotem())
            {
                return false;
            }

            var nTargetTeam = rUnit.teamIndex;
            var rRelation = BattleUtil.CheckRelation(this.self, rUnit);
            if ((this.targetRelation & rRelation) != 0)
            {
                return this.OnCondition(rTarget);
            }

            return false;
        }

        private void OnHit(List<CollisionComponent> rResult, List<Unit> rTargets)
        {
            for (int i = 0; i < rResult.Count; i++)
            {
                var rUnit = rResult[i].unit;
                if (rUnit != null)
                {
                    rTargets.Add(rUnit);
                }
            }
        }

        protected void CollisionCheck(ColliderProxy rProxy, ref List<Unit> rTargets)
        {
            this.self.battle.playCtrl.collisionCtrl.CheckCollision(rProxy, this.mOnHit, ref rTargets, this.mCondition);
        }

        public virtual void TrySelect(SelectParam rParam, LVector2 rSelfPos, ref List<Unit> rTargets)
        {
            
        }

        public void Select(SelectParam rParam)
        {
            this.targets.Clear();
            this.TrySelect(rParam, this.self.pos, ref this.targets);
        }

        /// <summary>
        /// TODO 暂时未处理合并执行 将目标中的重复目标筛选出来作为次数统计
        /// </summary>
        public void Screen()
        {
            this.targetsScreen.Clear();
            for (int i = 0; i < this.targets.Count; i++)
            {
                var rTarget = this.targets[i];
                this.targetsScreen.TryAdd(rTarget, 0);
                this.targetsScreen[rTarget]++;
            }
        }
        
        protected virtual void OnInitialize(TargetSelectConfig rConfig)
        {
        }
        protected virtual void OnInitialize(IReadOnlyList<int> rTabConfig)
        {
        }

        protected virtual bool OnCondition(CollisionComponent rTarget)
        {
            return true;
        }
        
        public virtual void Free()
        {
            ClassPool.Put(this);
        }
    }

    public class SelectParam : IReusableClass
    {
        public Unit unit;
        public LVector2 pos;
        public LVector2 aspect;
        
        public uint MaxStore => 20;
        public void OnReset()
        {
            this.unit = null;
            this.pos = LVector2.zero;
            this.aspect = LVector2.zero;
        }

        public void Serialize(SOutputStream _buf)
        {
            
        }

        public void DeSerialize(SInputStream _buf)
        {
            
        }
    }
}